Bom 和 Ajax

【金山文档】 Bom和Ajax

https://kdocs.cn/l/cnWuvzdJqqOU

复习: 回调函数

(一) window对象

JavaScript运行在浏览器, 而window对象是浏览器提供的一个对象, 所以也可以称为宿主对象。window包含Dom和Bom和其它的一些全局对象和方法, EcmaScript则是运行在浏览器上, window为EcmaScript提供了全局作用域.

(1) 浏览器缓存

问题1: 浏览器本地缓存有哪些

问题2: cookie、sessionStorage、localStorage有什么区别

相同点:

cookie,sessionStorage,localStorage都是存放在客户端(浏览器端),都是浏览器缓存

不同点:

  1. 作用不一样

    cookie数据始终在同源的http请求中携带,在浏览器和服务器来回传递,而sessionStorage,localStorage仅在本地(l浏览器)保存

  2. 大小限制区别

    cookie数据不超过4kb,sessionStorage和localStorage最大为5M, sessionStorage和localStorage是html5新特性

  3. 数据有效期不同

    • cookie在设置的(服务器设置)有效期内有效,不管窗口和浏览器关闭
    • sessionStorage仅在当前浏览器窗口关闭前有效,关闭即销毁(临时存储)
    • localStorage始终有效,用于持久化的本地存储,除非主动删除数据,否则不会过期
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>

  <script>
    // sessionStorage存数据
    sessionStorage.setItem('username','张三');
    sessionStorage.setItem('age',18);

    // sessionStorage取数据
    var username = sessionStorage.getItem('username');
    console.log(username);
    var age = sessionStorage.getItem('age');
    console.log(age); 
    // 清除
    sessionStorage.removeItem('username');


    // localStorage存数据
    localStorage.setItem("username","李四");
    // localStorage取数据
    var username = localStorage.getItem('username');
    console.log(username);
    // 全部清除
    localStorage.clear();
  </script>
</body>
</html>

api总结:

  1. 存数据 setItem('名称', 值);
  2. 取数据 getItem('名称');
  3. 移除数据 removeItem('名称');
  4. 全部清除 clear();

注意:

  1. 数据存入缓存都变成了字符串
  2. 需要存对象的时, 需要先将对象转成json字符串

(2) window的一些方法

  1. JSON

    • JSON数据格式

    • JSON.stringfy()

    • JSON.parse();

  2. open();

  3. eval(); // 略

  4. parseInt() 和 parseFloat(); // 略

  5. encodeURI() 和 decodeURI();

  6. setTimout() 和clearTimeout();

  7. setInterval() 和 clearInterval();

01 JSON

1. json数据格式

json数据是一种轻量级的数据格式, 非常方便在互联网上传输, 它的格式如下:

  1. 一般是对象或者数组, 服务器端返回给前端的一般就是这种数据格式
  2. 以键值对存储,键名必须是双引号, 值如果是字符串也必须是双引号, 最后一个键值对不能加逗号(普通对象可以加)
[
    {
        "username": "张三",
        "age": 18
    },
    {
        "username": "张三2",
        "age": 18
    },
    {
        "username": "张三3",
        "age": 18
    }
]
2. 对象和json字符串互转
var obj = {username: '张三', age: 18};
// 对象转json字符串
var str = JSON.stringify(obj);
typeof str; // string

// str2是个符合json数据格式的字符串
var str2 = '{"username":"张三","age":18}';
// json字符串转对象
var obj2 = JSON.parse(str2);
typeof obj2;  // object
3. JSON应用

localStorage和sessionStorage无法存对象, 能存字符串, 所以我们想存放对象, 可以先将对象转成字符串, 需要使用的时候, 再讲字符串转成对象, 举例: 将张三对象存取

var person = {username:'张三', age:18};
// 1.将对象转成json字符串
var str = JSON.stringfy(person);
// 2.将字符串存入缓存
localStorage.setItem('person',str);

/* 获取数据 */
// 1.将数据取出
var person =localStorage.getItem('person');
// 2.将字符串person转成对象
person = JSON.parse(person);
console.log(person);

02 window的其它方法

// 打开一个窗口
window.open('http://www.baidu.com');
// 将url编码
var url = 'http://huruqing.cn:3003?username=张三&age=18";
var newUrl = encodeURI(url);
// 解码
var newUrl = decodeURI(newUrl);

// 延迟执行
var timer = setTimeout(function(){
    alert(2222);
}, 3000);
// 清除延迟器
clearTimeout(timer);

// 定时器
var count = 60;
var timer = setInterval(function() {
    console.log(--count);
    if (count === 0) {
        // 清除定时器
		clearInterval(timer);
	}
},1000);

(二) BOM是什么

浏览器对象模型(Browser Object Model)简称 BOM, 浏览器对象模型 (BOM) 使 JavaScript 有能力与浏览器"对话"。

BOM对象包含了以下内容:

  1. location:包含当前网页文档的 URL 信息。
  2. history:包含浏览器窗口访问过的 URL 信息。
  3. navigator:包含客户端有关浏览器信息。
  4. screen:包含客户端屏幕的信息。
  5. frames: 返回窗口中所有命名的框架。
  6. XMLHttpRequest: 用来创建ajax对象的构造函数

1. location

包含当前网页文档的 URL 信息。

2. history

包含浏览器窗口访问过的 URL 信息。

  • history.back(); // 后退
  • history.forward(); // 前进
  • history.go(); // go(1)前进一个记录, go(-1)后退一个记录

3.navigator

包含客户端有关浏览器信息。主要用到的是navigator.userAgent

// 判断用户使用的设备是pc还是移动端,可以使用|添加更多设备类型 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script>
        if (navigator.userAgent.match(/ipad|iphone|android|playbook/i)){
            console.log('这是移动端');
            location.href = 'https://m.maizuo.com/v5/#/films/nowPlaying';
        } else {
            console.log('这是pc端')
            location.href = 'https://www.maizuo.com/#/';
        }
    </script>
</head>
<body> 
</body>
</html>

(三) Ajax

Ajax知识点

  1. 什么是ajax?
  2. 创建一个ajax请求的过程(如何从服务器获取数据)
  3. 查看网络请求
  4. get请求和post请求区别
  5. http状态码
  6. 跨域请求

1. 什么是ajax?

AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。

AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。

解释: 在没有ajax之前, 更新页面需要重新加载整个页面, 填一个表单, 然后提交, 如果失败了, 重新提交需要重新填写整个表单

2. ajax创建过程

概念: 接口接口地址, 接口是服务器给前端提供数据的出口(服务器接口), 接口地址, 就是接口所在的位置

前端可以使用ajax请求接口从而获得服务器提供的数据, 以下是请求数据的全过程(步骤)

  1. 创建异步ajax请求对象

  2. 设置请求的参数

    • 请求方法 get或post
    • 请求参数
  3. 发送请求

  4. 注册(绑定)事件

  5. 获取返回数据

    ajax创建过程

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    <body> 
      <h3>用户列表</h3>
      <ol>
        <!-- 具体用户 -->
      </ol> 
        
      <script>
        //1.创建ajax对象
        var xhr = new XMLHttpRequest();
        //2.设置请求参数: 请求方法get|post,请求参数
        xhr.open('GET','http://huruqing.cn:3009/getUsers');
        //3. 发送请求
        xhr.send();
        //4. 注册处理请求的事件和函数
        xhr.onreadystatechange = function() {
          console.log(xhr.readyState);
          // readyState为4,代表已经跟服务器连接上了
          // status为200, 代表服务器返回了成功的数据
          if(xhr.readyState === 4 && xhr.status === 200) {
            // responseText是服务器给前端返回的数据
            // console.log(typeof xhr.responseText);
            // console.log(xhr.responseText);
            // 将json字符串转为数组或者对象
            var list = JSON.parse(xhr.responseText);
            console.log(list);
          } 
        }
      </script>
    </body>
    </html>
    

    ajax请求参数

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    
    <body>
    
        <script>
            // 封装成一个函数
            function getUser(userId) {
                var xhr = new XMLHttpRequest();
                xhr.open('get', 'http://huruqing.cn:3009/getUserDetail?userId='+userId);
                xhr.send();
                xhr.onreadystatechange = function () {
                    if (xhr.readyState === 4 && xhr.status === 200) {
                        var data = JSON.parse(xhr.responseText);
                        console.log(data);
                    }
                }
            }
            getUser('92be12aba9b01f');
            getUser('b3e6758a5490e5'); 
        </script>
    </body> 
    </html>
    

3. 查看网络请求

  1. 认识浏览器控制台

    1. 元素
    2. 控制台
    3. 来源: 源代码
    4. 网络: 查看网络请求
    5. 其它....

    image-20220103125116392

  2. 网络一栏

    1. http请求: 一个图片, 一个css文件, 一个js文件这些都是从服务器端取回来的, 都叫一个http请求, XHR请求就是ajax请求了
    2. 过滤: 搜索某个网络请求
    3. 双击一个xhr请求, 就能查看到请求的详细信息
  3. ajax请求详解

    1. 请求消息
      • 常规消息
      • 请求头
      • 响应头
    2. 载荷: 请求参数
    3. 预览: 服务器返回数据预览
    4. 响应: 服务器返回的数据
    5. 其它...

    image-20220103125720199

4. get请求和post区别

  1. 用途不一样

    • get 一般用于获取数据: 数据事先存在服务器, 通过get请求去获取
    • post 一般用于发送数据: 比如用户注册, 用户填好表单后, 通过post把数据传给服务器, 服务器再将数据存入数据库

    ps: 实际项目中, 也并非一定要这么做, 具体情况根据公司实际情况处理, 后台一般会提供接口文档, 指定请求方法

  2. 传递参数方式不一样

    • get请求如果需要传递参数,那么会默认将参数拼接到url的后面;然后发送给服务器;get请求传递参数大小是有限制的;是浏览器的地址栏有大小限制;
    • post传递参数,需要把参数放进请求体中,发送给服务器;post请求参数放进了请求体中,对大小没有要求;
  3. 安全性问题

    • get安全性相对较低
    • post安全性相对比较高;

    ps: 安全性是相对而言的, 网页的安全性其实不管用那种方式, 安全性都很难很高, 因为别人甚至可以绕过浏览器去请求数据, 所以在实际项目中, 一般前端要校验数据, 后端也要校验数据

  4. 浏览器缓存

    • get 一般会走缓存,为了防止走缓存,给url后面每次拼的参数不同;放在?后面,一般用个时间戳
    • post请求不会走缓存;
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <script>
        // get请求
        function aa(userId) {
            var xhr = new XMLHttpRequest();
            xhr.open('get', 'http://huruqing.cn:3009/getUserDetail?userId='+userId);
            xhr.send();
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    var data = JSON.parse(xhr.responseText);
                    console.log('get请求',data);
                }
            }
        }
        aa('92be12aba9b01f'); 


        // post请求
        function bb(userId) {
            var xhr = new XMLHttpRequest();
            xhr.open('post', 'http://huruqing.cn:3009/getUserDetail');
            //  Content-Type 字段来获知请求中的消息主体是用何种方式编码,再对主体进行解析。
            xhr.setRequestHeader('content-type','application/x-www-form-urlencoded; charset=UTF-8');
            xhr.send('userId='+userId);
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    var data = JSON.parse(xhr.responseText);
                    console.log('post请求',data);
                }
            }
        }
        bb('92be12aba9b01f');  
    </script>
</body> 
</html>

5. http状态码

上面代码中的 xhr.readyState === 4 && xhr.status 含义

xhr.readyState (了解)

当发送一个请求后,客户端需要确定这个请求什么时候会完成,因此,XMLHttpRequest对象提供了onreadystatechange事件机制来捕获请求的状态,继而实现响应。

XHR.readyState 请求就绪状态(0,1,2,3,4),而且状态也是不可逆的:

0:请求未初始化,还没有调用 open()。

1:请求已经建立,但是还没有发送,还没有调用 send()。

2:请求已发送,正在处理中(通常现在可以从响应中获取内容头)。

3:请求在处理中;通常响应中已有部分数据可用了,没有全部完成。

4:响应已完成;您可以获取并使用服务器的响应了。

xhr.status 就是http状态码了

https://www.runoob.com/http/http-status-codes.html

重点几个:

200 请求成功。一般用于GET与POST请求

301 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替

302 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI。301和302都叫地址重定向, 一个是永久重定向, 一个是临时重定向

304 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源

403 服务器理解请求客户端的请求,但是拒绝执行此请求

404 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面

405 客户端请求中的方法被禁止

500 服务器内部错误,无法完成请求

6. 跨域请求

1. 跨域请求相关知识

什么叫跨域,浏览器有同源策略,只有当“协议”、“域名”、“端口号”都相同时,才能称之为是同源,其中有一个不同,即是跨域。

同源策略的作用是什么呢?同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。

那么我们又为什么需要跨域呢?一是前端和服务器分开部署,接口请求需要跨域,二是我们可能会加载其它网站的页面作为iframe内嵌。

跨域的方法有哪些?

  1. jsonp跨域

  2. cors跨域

    jsonp 只能支持 get 请求,cors 可以支持多种请求。cors是在服务器端设置, cors 并不需要前端做什么工作。

  3. proxy(代理)跨域

    • nginx 反向代理(运营或后台)
    • webpack设置proxy跨域(前端)
  4. websocket跨域

  5. postMessage

  6. 其它方式跨域

    • window.name + iframe
    • location.hash + iframe
    • document.domain

2. jsonp跨域

问题1: 问什么说jsonp不算真正的ajax?

  1. ajax的核心是通过xmlHttpRequest获取非本页内容 jsonp的核心是动态添加script标签调用服务器提供的js脚本
  2. jsonp只支持get请求,ajax支持get和post请求

问题2: jsonp跨域原理是什么?

尽管浏览器有同源策略,但是 <script> 标签的 src 属性不会被同源策略所约束,可以获取任意服务器上的脚本并执行。jsonp 通过插入script标签的方式来实现跨域,参数只能通过url传入,仅能支持get请求。

json跨域步骤:

方式一:

  1. 创建用户接收数据的方法,比如getData
  2. 添加script标签, src地址指向了jsonp接口地址,带上参数callback=getData
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body> 
     
  <script>
    function getData(data) {
      console.log(data);
    }
  </script>
  <script src="http://huruqing.cn:3009/getData?callback=getData"></script>
</body> 
</html>

方式二:

使用动态创建script的方式

  1. 创建用户接收数据的方法,比如getData

  2. 动态插入script标签

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body> 
     
  <script>
    function getData(data) {
      console.log(data);
    }

    var script =document.createElement('script');
    script.src = 'http://huruqing.cn:3009/getData?callback=getData';
    document.body.appendChild(script); 
  </script> 
</body> 
</html>

注意事项: jsonp接口跟普通接口不太一样, 需要服务器端做特殊处理

(四) 同步和异步

1. 同步和异步是什么

同步: 同一时间只做一件事, 做完一件事之后才开始做下一件事

异步: 同一时间做多件事

拿做一顿饭举例:

方案1(同步):

  1. 第一步: 先做饭, 然后坐等饭煮熟
  2. 第二步: 开始洗菜, 洗锅, 然后开始炒菜
  3. 第三步: 饭菜上桌开始吃饭

方案2(异步):

  1. 第一步: 做饭, 做饭的同时开始洗菜, 洗锅, 炒菜
  2. 第二步: 饭熟, 菜也熟了, 上桌吃饭

方案1就是同步

缺点: 速度慢, 优点: 调理清晰

方案2就是异步

缺点: 同时做多件事, 容易乱, 比如一个大厨同时炒几个菜, 经验不足容易手忙脚乱

优点: 效率高

2. js中的同步和异步

在js中是先执行同步操作再执行异步操作

  1. setTimeout

    
    
  2. ajax请求

    • ajax默认是异步请求, 所以data的值为undefined, 因为程序并不会等待ajax请求完成才继续往下执行, 而是一边请求一边往下执行
    
    
    • ajax也可设置为同步请求

      open的第三个参数设置为true, 则ajax请求是同步, 默认为false(异步请求)

    
    

(五) 封装ajax请求的库

  1. jQuery.js封装有请求ajax的方法

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head> 
    <body> 
         
      <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
      <script>
        $.ajax({
          type: 'get',
          url: 'http://huruqing.cn:3009/getUserDetail',
          data: {  // 请求参数
            userId: '92be12aba9b01f'
          },
          dataType: 'json', // 返回的数据
          success: function(res) {  // 成功的回调
            console.log(res);
          },
          error: function() {  // 失败的回调
            alert('请求失败了')
          }
        });
      </script> 
    </body> 
    </html>
    
  2. axios一个只封装了ajax请求的库, 目前最流行

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    
    <body>
    
      <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.24.0/axios.min.js"></script>
      <script>
        var url = 'http://huruqing.cn:3009/getUserDetail';
        axios.get(url, { params: { userId: '92be12aba9b01f' } }).then(function (res) {
          console.log(res);
        }).catch(function () {
          alert('请求失败了');
        })
    
        axios.post(url, {userId: '92be12aba9b01f'}).then(function (res) {
          console.log(res);
        }).catch(function () {
          alert('请求失败了');
        })
      </script>
    </body> 
    </html>
    

(六) 作业

1. 完成影院列表

接口地址: http://81.71.65.4:3008/cinema/list

请求方法: get

请求参数: cityName 值可以是北上广深四个城市


2. 完成登录页面

  1. 输入手机号码, 点击获取验证按钮, 发送请求到服务器去获取验证码, 然后开始倒计时
  2. 输入验证码, 点击登录, 发送请求到服务器去登录, 成功后跳转到个人中心页面
  3. 登录成功之后, 将手机号码存储本地缓存
  4. 个人中心页面: 获取本地缓存的手机号码, 有号码则显示电话号码, 没有号码, 显示立即登录

接口:

获取验证码接口:

地址: http://huruqing.cn:3003/user/getSmsCode 请求参数: phone

请求方法: get

登录接口:

接口地址: http://huruqing.cn:3003/user/login

请求方法: post

请求参数: phone: xxx, smsCode:xxx

作业思路:

点击获取验证码, 要做什么事情

  1. 检查电话号码是否为空, 长度是不是11
  2. 发送请求到服务器, 获取验证码
  3. 按钮倒计时

点击登录的逻辑

  1. 获取手机号码和验证码
  2. 把号码和验证码发送到服务器去登录
  3. 登录成功后, 把手机号码缓存起来, 跳转到个人中心页面

个人中心页面逻辑

  1. 从缓存获取手机号码
  2. 有号码, 就显示号码, 显示退出登录按钮, 隐藏立即登录按钮
  3. 若无号码, 就显示立即登录按钮, 隐藏手机号码和退出登录按钮

点击退出登录逻辑

  1. 清除缓存里的手机号码
  2. 显示立即登录
  3. 清空并隐藏手机号码, 隐藏退出登录按钮
<!-- 个人中心代码 -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body> 
  <h3>个人中心</h3>
  <div id="phone" style="display: none;">xxxxx</div>
  <a id="login" href="./login.html">立即登录</a> 
  <a id="logout" href="#"  style="display: none;">退出登录</a>

  <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
  <script>
     
  </script>
</body>
</html>
<!-- 登录页面代码 -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <p><input id="phone" type="text" placeholder="手机号码" maxlength="11" value="13800000000"></p>
    <p><input type="text" placeholder="验证码" id="smsCode"> <button id="code">获取验证</button></p>
    <button id="login">立即登录</button>



    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script>
      
    </script>
</body>
</html>